// Matlab style plot functions for OpenCV by Changbo (zoccob@gmail).
// plot and label:
//
// template<typename T>
// void plot(const string figure_name, const T* p, int count, int step = 1,
//		     int R = -1, int G = -1, int B = -1);
//
// figure_name: required. multiple calls of this function with same figure_name
//              plots multiple curves on a single graph.
// p          : required. pointer to data.
// count      : required. number of data.
// step       : optional. step between data of two points, default 1.
// R, G,B     : optional. assign a color to the curve.
//              if not assigned, the curve will be assigned a unique color automatically.
//
// void label(string lbl):
//
// label the most recently added curve with lbl.
//
// 
//
//

#pragma once

#if WIN32
#   ifndef CVPLOT_snprintf
#       define CVPLOT_snprintf sprintf_s
#   endif
#endif 

// STD 
#include <vector>

// OPENCV
//#include <cv.h>
//#include <highgui.h>
#include <opencv2/core/core.hpp>

// Qt4 if defined
#ifdef HAS_QT4
#include <QWidget>
#endif



#if (defined WIN32 || defined _WIN32 || defined WINCE) && defined CVPLOT_EXPORTS
#  define CVPLOT_DLL_EXPORTS __declspec(dllexport)
#else
#  define CVPLOT_DLL_EXPORTS
#endif

#ifdef CVPLOT_DOUBLE_PRECISION
typedef double FLOAT;
#define FLOAT_MIN DBL_MIN
#define FLOAT_MAX DBL_MAX
#define OCV_FLOAT_TYPE CV_64F
#else
typedef float FLOAT;
#define FLOAT_MIN FLT_MIN
#define FLOAT_MAX FLT_MAX
#define OCV_FLOAT_TYPE CV_32F
#endif


namespace CvPlot
{
// A curve.
struct Series
{
    // number of points
    unsigned int count;
    FLOAT *data;
    // name of the curve
    std::string label;

    // allow automatic curve color
    bool auto_color;
    cv::Scalar color;

    Series(void);
    Series(int n, FLOAT * p);
    Series(const Series& s);
    ~Series(void);

    // release memory
    void Clear();

    void SetData(int n, FLOAT *p);

    void SetColor(cv::Scalar color, bool auto_color = true);
    void SetColor(int R, int G, int B, bool auto_color = true);
};

// a figure comprises of several curves
class Figure
{
public:
    Figure(const std::string & name);
    ~Figure();

    std::string GetFigureName() const ;
    Series* Add(Series *s);
    void Clear();
    void DrawLabels(cv::Mat & output, int posx, int posy);

    // show plot window
    void Show();
#ifdef HAS_QT4
    QWidget * GetWidget();
#endif


private:
    Figure();

    void DrawAxis(cv::Mat & output);
    void DrawPlots(cv::Mat & output);

    // call before plot
    void Initialize();
    cv::Scalar GetAutoColor() const;
    // window name
    std::string figure_name;
    cv::Size figure_size;

    // margin size
    int    border_size;

    cv::Scalar backgroud_color;
    cv::Scalar axis_color;
    cv::Scalar text_color;

    // several curves
    std::vector<Series*> plots;

    // manual or automatic range
    bool custom_range_y;
    FLOAT y_max;
    FLOAT y_min;

    FLOAT y_scale;

    bool custom_range_x;
    FLOAT x_max;
    FLOAT x_min;

    FLOAT x_scale;

    // automatically change color for each curve
    int color_index;


};

// manage plot windows
class PlotManager
{
public:

    // now useless
    bool HasFigure(const std::string &wnd);
    Figure* FindFigure(const std::string &wnd);

    void Plot(const std::string &figure_name, const FLOAT* p, int count, int step,
              int R, int G, int B);

    void Plot(const std::string &figure_name, cv::Mat & dataInFloat, int count,
              int R, int G, int B);

#ifdef HAS_QT4
    QWidget * GetPlotWidget(const std::string &figure_name, cv::Mat & dataInFloat, int count, int R, int G, int B);
#endif

    void Label(const std::string &lbl);
private:
    std::vector<Figure*> figure_list;
    Series *active_series;
    Figure *active_figure;
};

// handle different data types; static methods;

//template<typename T>
//CVPLOT_DLL_EXPORTS void plot(const std::string & figure_name, const T* p, int count, int step = 1,
//		  int R = -1, int G = -1, int B = -1);

CVPLOT_DLL_EXPORTS void plot(const std::string & figure_name, const cv::Mat & oneDimData, int count=0, int R = -1, int G = -1, int B = -1);

#ifdef HAS_QT4
CVPLOT_DLL_EXPORTS QWidget * getPlotWidget(const std::string & figure_name, const cv::Mat & oneDimData, int count=0, int R = -1, int G = -1, int B = -1);
#endif

CVPLOT_DLL_EXPORTS void clear(const std::string & figure_name);

CVPLOT_DLL_EXPORTS void label(const std::string & lbl);

} // namespace
